package com.djakapm.markdown.editor.component;

import com.djakapm.markdown.editor.AppConstant;
import com.djakapm.markdown.editor.Engine;
import com.djakapm.markdown.editor.component.action.*;
import com.djakapm.markdown.editor.component.listener.MarkdownTextEditorContextMenuListener;
import com.djakapm.markdown.editor.component.listener.TextChangeKeyListener;
import com.djakapm.markdown.editor.util.ResourceManager;
import com.djakapm.swing.component.tab.Tab;
import org.apache.commons.io.FilenameUtils;

import javax.swing.*;
import javax.swing.text.DefaultEditorKit;
import javax.swing.undo.UndoManager;
import java.io.File;

public class EditorComponentPresenter {
    private Engine engine;
    private String markupContent;
    private String markdownContent;
    private File document;
    private EditorComponentView view;
    private boolean contentModified;
    private Action undoAction;
    private Action redoAction;
    private Action saveFileAction;
    private Action updateViewAction;
    private UndoManager undoManager;
    private TextChangeKeyListener keyListener;
    private Action copyToClipboardAction;
    private Action viewSourceAction;
    private boolean sourceMode = true;
    private MarkdownTextEditorContextMenuListener markdownTextEditorContextMenuListener;


    public EditorComponentPresenter(Tab tab){
        this(tab,null);
    }

    public EditorComponentPresenter(Tab tab,File document){
        this.undoManager = new UndoManager();
        this.engine = new Engine();
        this.document = document;
        this.setView(new EditorComponentView(tab));
        this.getView().init();
        this.createActions();

        this.addTextAreaDefaultActions();
        this.getView().getMarkdownTextEditor().getPopupMenu().addSeparator();
        this.addActions();
        
        this.getView().getMarkdownTextEditor().configureEditor(this.undoManager,
                this.keyListener,this.markdownTextEditorContextMenuListener,
                this.saveFileAction,this.updateViewAction,this.undoAction,this.redoAction);
        this.addActionToToolBar(this.getView().getMarkdownTextEditor().getToolBar(),
                this.saveFileAction,
                null,
                this.undoAction,
                this.redoAction,
                null,
                this.updateViewAction
        );

        this.addActionToToolBar(this.getView().getMarkupView().getToolBar(),
                this.viewSourceAction,
                this.copyToClipboardAction
        );
        if(this.document == null){
            this.createDocument();
        }
        else{
            this.openDocument();
        }
        this.synchronizeEditorsWithContents();
        this.resetUndoManager();
    }

    private void addActions() {
        this.getView().getMarkdownTextEditor().getPopupMenu()
                .add(this.saveFileAction);
        this.getView().getMarkdownTextEditor().getPopupMenu()
                .add(this.undoAction);
        this.getView().getMarkdownTextEditor().getPopupMenu()
                .add(this.redoAction);
        this.getView().getMarkdownTextEditor().getPopupMenu()
                .add(this.updateViewAction);
    }

    private void addTextAreaDefaultActions() {
        ActionMap am;
        Action a;

        am = this.getView().getMarkdownTextEditor().getEditorActionMap();
        a = am.get(DefaultEditorKit.cutAction);
        a.putValue(Action.NAME, "Cut");
        a.putValue(Action.SMALL_ICON, ResourceManager.getIcon(AppConstant.CUT_ICON_NAME));
        this.getView().getMarkdownTextEditor().getPopupMenu().add(a);

        a = am.get(DefaultEditorKit.copyAction);
        a.putValue(Action.NAME, "Copy");
        a.putValue(Action.SMALL_ICON, ResourceManager.getIcon(AppConstant.COPY_ICON_NAME));
        this.getView().getMarkdownTextEditor().getPopupMenu().add(a);

        a = am.get(DefaultEditorKit.pasteAction);
        a.putValue(Action.NAME, "Paste");
        a.putValue(Action.SMALL_ICON, ResourceManager.getIcon(AppConstant.PASTE_ICON_NAME));
        this.getView().getMarkdownTextEditor().getPopupMenu().add(a);

        a = am.get(DefaultEditorKit.selectAllAction);
        a.putValue(Action.NAME, "Select All");
        this.getView().getMarkdownTextEditor().getPopupMenu().add(a);
    }

    public boolean isContentModified(){
        return this.contentModified;
    }
    
    public void copyContentToClipboard(){
        this.getView().getMarkupView().copyContentToClipboard();
    }

    public void sourceMode(){
        this.getView().getMarkupView().sourceMode();
    }

    public void renderMode(){
        this.getView().getMarkupView().renderMode();
    }

    public void undoEdit(){
        if(this.undoManager.canUndo()){
            this.undoManager.undo();
        }
    }

    public boolean canUndoEdit(){
        return this.undoManager.canUndo();
    }

    public void redoEdit(){
        if(this.undoManager.canRedo()){
            this.undoManager.redo();
        }
    }

    public boolean canRedoEdit(){
        return this.undoManager.canRedo();
    }

    private void createActions() {
        this.undoAction = new UndoAction(this);
        this.redoAction = new RedoAction(this);
        this.updateViewAction = new UpdateViewAction(this);
        this.saveFileAction = new SaveFileAction(this);
        this.keyListener = new TextChangeKeyListener(this);
        this.markdownTextEditorContextMenuListener = new MarkdownTextEditorContextMenuListener(this);
        this.copyToClipboardAction = new CopyToClipboardAction(this);
        this.viewSourceAction = new ViewSourceAction(this);

    }

    public void addActionToToolBar(JToolBar toolbar, Action... actions){
        for(Action action:actions){
            if(action == null){
                toolbar.addSeparator();
            }
            else{
                toolbar.add(action);
            }
        }
    }

    public boolean isSourceMode(){
        return this.sourceMode;
    }

    public void setSourceMode(boolean sourceMode){
        this.sourceMode = sourceMode;
    }

    public void updateView(){
        this.synchronizeContents();
        this.getView().getMarkupView().setEnabled(true);
    }

    public void openDocument(){
        this.markdownContent = this.engine.openDocument(this.document);
        this.markupContent = this.engine.convert(this.markdownContent);
    }

    public void createDocument(){
        this.markdownContent = "";
        this.markupContent = "";
    }

    public String getMarkupContent(){
        return this.markupContent;
    }

    public String getMarkdownContent(){
        return this.markdownContent;
    }

    public File getDocument(){
        return this.document;
    }

    public void setDocument(File document){
        this.document = document;
    }

    public void setTitle(String title){
        this.getView().setTitle(title);
    }

    public void synchronizeEditorsWithContents(){
        this.getView().getMarkupView().setText(this.getMarkupContent());
        this.getView().getMarkdownTextEditor().setText(this.getMarkdownContent());
    }

    public File saveContent(String selectedFilePath){
        return this.engine.saveContent(selectedFilePath,this.markdownContent,this.markupContent);
    }

    public void synchronizeContents(){
        this.markdownContent = this.view.getMarkdownContent();
        this.markupContent = this.engine.convert(this.markdownContent);
        this.view.setMarkupContent(this.markupContent);
    }

    public void reevaluateActions(){
        this.undoAction.setEnabled(this.undoManager.canUndo());
        this.redoAction.setEnabled(this.undoManager.canRedo());
        this.saveFileAction.setEnabled(this.isContentModified());
        this.updateViewAction.setEnabled(this.isContentModified());
    }



    public void saveContent(){
        this.synchronizeContents();
        if(this.getDocument() == null){
            this.saveToNewFile();
        }
        else{
            this.saveToExistingFile();
        }
        this.reevaluateActions();
    }

    private boolean isFilenameContainExtension(String fileName){
        return FilenameUtils.isExtension(fileName, AppConstant.DEFAULT_INPUT_FILE_EXT_LABEL);
    }

    private void saveToNewFile() {
        String selectedFilePath;
        this.getView().showSaveDialog();

        if(!this.getView().hasSelectedFile()){
            return;
        }

        selectedFilePath = this.getView().getSelectedFilePath();
        String fileName = FilenameUtils.getName(selectedFilePath);

        if(!isFilenameContainExtension(fileName)){
            fileName += AppConstant.DEFAULT_INPUT_FILE_EXT;
        }

        this.setTitle(fileName);
        this.setDocument(this.saveContent(selectedFilePath));
        this.setContentModified(false);
    }

    private void saveToExistingFile() {
        String selectedFilePath = this.getDocument().getPath();
        String fileName = FilenameUtils.getName(selectedFilePath);
        this.setTitle(fileName);
        this.saveContent(selectedFilePath);
        this.setContentModified(false);
    }

    public void setContentModified(boolean contentModified) {
        this.contentModified = contentModified;
    }

    public void resetUndoManager(){
        this.undoManager.discardAllEdits();
        this.reevaluateActions();
    }

    public EditorComponentView getView() {
        return view;
    }

    public void setView(EditorComponentView view) {
        this.view = view;
    }
}
